package com.un.ebs.product.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.core.common.KeyValueDto;
import com.un.ebs.core.enums.PowerTypeEnum;
import com.un.ebs.core.exception.BusinessDataRepeatException;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.power.PowerResourceObject;
import com.un.ebs.core.power.PowerResourceSet;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.customer.service.CustomerService;
import com.un.ebs.customer.service.CustomerTraceService;
import com.un.ebs.order.domain.OrderItemExt;
import com.un.ebs.order.enums.OrderStatusEnum;
import com.un.ebs.order.mapper.OrderItemExtMapper;
import com.un.ebs.product.ProductConfigureCode;
import com.un.ebs.product.domain.*;
import com.un.ebs.product.dto.*;
import com.un.ebs.product.enums.ProductChargeTypeEnum;
import com.un.ebs.product.enums.ProductSkuResourceStatusEnum;
import com.un.ebs.product.enums.ProductUnitTypeEnum;
import com.un.ebs.product.mapper.*;
import com.un.ebs.product.service.ProductClassAttrService;
import com.un.ebs.product.service.ProductClassAttrValueService;
import com.un.ebs.product.service.ProductImageService;
import com.un.ebs.product.service.ProductService;
import com.un.ebs.sys.dto.ObjectParentAndIndexChangeDto;
import com.un.ebs.sys.service.AppPowerService;
import com.un.ebs.sys.service.ConfigureService;
import com.un.ebs.sys.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;


/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author liubo
 * @since 2019-09-16
 */
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {

    @Resource
    private ProductAttrValueMapper productAttrValueMapper;

    @Resource
    private ProductAttrValueExtMapper productAttrValueExtMapper;

    @Resource
    private ProductClassAttrMapper productClassAttrMapper;

    @Resource
    private ProductSkuMapper productSkuMapper;

    @Resource
    private ProductSkuItemMapper productSkuItemMapper;

    @Resource
    private ProductOrderCommentExtMapper productOrderCommentExtMapper;

    @Resource
    private ProductExtMapper productExtMapper;

    @Resource
    private ProductSkuExtMapper productSkuExtMapper;

    @Resource
    private AppPowerService appPowerService;

    @Resource
    private CustomerTraceService customerTraceService;

    @Resource
    private CustomerService customerService;

    @Resource
    private UserService userService;

    @Resource
    private ProductClassAttrService productClassAttrService;

    @Resource
    private ProductClassAttrValueService productClassAttrValueService;

    @Resource
    private ProductImageService productImageService;

    @Resource
    private OrderItemExtMapper orderItemExtMapper;

    @Resource
    private ConfigureService configureService;

    private Double getInitInventoryQty() {
        String qty = configureService.getValueByCode(ProductConfigureCode.sku_init_inventory_qty, SecurityUtils.getTenantId());
        if (StringUtils.isNullOrEmpty(qty)) {
            return 0.0;
        } else {
            return Double.valueOf(qty);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String add(ProductDto req) {
        return add(req, true);
    }

    @Override
    public String add(ProductDto req, boolean isNotRepeatCode) {
        List<ProductDto> list = new ArrayList<>();
        list.add(req);
        List<String> ret = add(list, isNotRepeatCode);
        if (StringUtils.isNullOrEmpty(ret)) {
            return null;
        } else {
            return ret.get(0);
        }
    }


    @Override
    public List<String> add(List<ProductDto> req) {
        return add(req, false);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> add(List<ProductDto> req, boolean isNotRepeatCode) {
        List<String> ret = new ArrayList<>();
        for (ProductDto reqObj : req) {
            if (isNotRepeatCode) {
                if (baseMapper.selectCountByCode(reqObj.getCode()) >= 1) {
                    throw new BusinessDataRepeatException("代码 【" + reqObj.getCode() + "】 已经存在，不能重复！");
                }
            }
            Product obj = new Product();
            obj.setCode(reqObj.getCode());
            obj.setName(reqObj.getName());
            obj.setClassId(reqObj.getClassId());
            obj.setSaleLargeClassId(reqObj.getSaleLargeClassId());
            obj.setSaleMediumClassId(reqObj.getSaleMediumClassId());
            obj.setSaleSmallClassId(reqObj.getSaleSmallClassId());
            obj.setUnitType(reqObj.getUnitType() == null ? ProductUnitTypeEnum.ProductQty : reqObj.getUnitType());
            obj.setChargeType(reqObj.getChargeType());
            obj.setPurchaseType(reqObj.getPurchaseType());
            obj.setPriceConfirmType(reqObj.getPriceConfirmType());
            obj.setSaleType(reqObj.getSaleType());
            obj.setBuyMinQty(reqObj.getBuyMinQty());
            obj.setBuyMaxQty(reqObj.getBuyMaxQty());
            obj.setPrice(reqObj.getPrice());
            obj.setIsDeliverFlow(reqObj.getIsDeliverFlow());
            obj.setIsDeliverAuditStatus(reqObj.getIsDeliverAuditStatus());
            obj.setIsMustDefunctByOrder(reqObj.getIsMustDefunctByOrder());
            obj.setIsMustDefunctTombSkuByOrder(reqObj.getIsMustDefunctTombSkuByOrder());
            obj.setRemark(reqObj.getRemark());
            obj.setSaleStart(reqObj.getSaleStart());
            obj.setSaleEnd(reqObj.getSaleEnd());
            obj.setIsDelete(false);
            obj.setIsBook(reqObj.getIsBook());
            obj.setPreTimeBookQty(reqObj.getPreTimeBookQty());
            obj.setWarehouseDesc(reqObj.getWarehouseDesc());
            obj.setSort(baseMapper.maxSortByClassId(reqObj.getClassId()));
            if (reqObj.getChargeType() == ProductChargeTypeEnum.ReadyPay) {
                obj.setChargeMinMoney(reqObj.getChargeMinMoney());
            } else {
                obj.setChargeMinMoney(0d);
            }
            obj.insert();
            ret.add(obj.getId());

            for (ProductAttrValueDto reqItem : reqObj.getAttrValues()) {
                if (StringUtils.isNullOrEmpty(reqItem.getValue())) {
                    continue;
                }
                ProductAttrValue productAttrValue = new ProductAttrValue();
                productAttrValue.setProductId(obj.getId());
                productAttrValue.setClassAttrId(reqItem.getAttrId());
                productAttrValue.setClassAttrValueId(reqItem.getClassValueId());
                productAttrValue.setValue(reqItem.getValue());
                productAttrValue.insert();
            }

            int cnt = updateSku(obj.getId());
            long saleCount = productClassAttrService.queryByClassId(reqObj.getClassId()).stream().filter(s -> s.getIsSale()).count();
            if (cnt == 0 && saleCount == 0) {
                // 默认SKU插入
                ProductSku sku = new ProductSku();
                sku.setProductId(obj.getId());
                sku.setSkuCode(obj.getCode());
                sku.setPrice(obj.getPrice());
                sku.setQty(getInitInventoryQty());
                sku.setIsDelete(false);
                sku.insert();
            }

        }
        return ret;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateSku(String productId) {

        // 重建 SKU
        List<List<ProductAttrValueExt>> dimAttrs = queryAttr(productId, true);
        if (dimAttrs.size() <= 0) {
            dimAttrs = queryAttr(productId, null);
        }
        List<List<ProductAttrValueExt>> result = new ArrayList<>();
        genSku(dimAttrs, result, new ArrayList<>(), 0);
        Product product = getById(productId);

        String qrcode = null;
        if (result.size() > 0) {
            // 将现有 SKU 作废
            LambdaQueryWrapper<ProductSku> lq = Wrappers.lambdaQuery();
            lq.eq(ProductSku::getProductId, productId);
            int cnt = productSkuMapper.selectCount(lq);
            if (cnt == 1) {
                // 如果SPU中只有一个SKU，则将SKU中的Qrcode继续保存到新的SKU中。
                qrcode = productSkuMapper.selectOne(lq).getQrcode();
            }
            productSkuMapper.delete(lq);

        }

        int i = 0;
        for (List<ProductAttrValueExt> sku : result) {
            i++;
            ProductSku obj = new ProductSku();
            obj.setProductId(product.getId());
            obj.setSkuCode(product.getCode() + "-" + i);
            obj.setPrice(product.getPrice());
            obj.setQty(getInitInventoryQty());
            obj.setIsDelete(false);
            obj.setQrcode(qrcode);
            obj.insert();

            for (ProductAttrValueExt value : sku) {
                ProductSkuAttrValue item = new ProductSkuAttrValue();
                item.setSkuId(obj.getId());
                item.setSpuAttrValueId(value.getId());
                item.insertOrUpdate();
            }
        }
        return result.size();
    }

    @Transactional
    @Override
    public void addInclude(String spuId, String includeSkuId, Double qty) {
        LambdaQueryWrapper<ProductSku> lq = Wrappers.lambdaQuery();
        lq.eq(ProductSku::getProductId, spuId);
        lq.eq(ProductSku::getIsDelete, false);
        List<String> ids = productSkuMapper.selectObjs(lq).stream().map(s -> s.toString()).collect(Collectors.toList());
        for (String skuId : ids) {
            LambdaQueryWrapper<ProductSkuItem> itemLq = Wrappers.lambdaQuery();
            itemLq.eq(ProductSkuItem::getSkuId, skuId);
            itemLq.eq(ProductSkuItem::getIncludeSkuId, includeSkuId);
            ProductSkuItem item = productSkuItemMapper.selectOne(itemLq);
            //productSkuItemMapper.selectBy(skuId, includeSkuId);
            if (item == null) {
                item = new ProductSkuItem();
                item.setSkuId(skuId);
                item.setIncludeSkuId(includeSkuId);
                item.setSort(productSkuItemMapper.maxSort());
            }
            item.setIsDelete(false);
            item.setQty(qty);
            item.insertOrUpdate();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void update(ProductDto req) {
        if (StringUtils.isNullOrEmpty(req.getId())) {
            throw new BusinessException("更新数据时，ID 值不能为空。");
        }

        if (baseMapper.selectCount2ByCode(req.getCode(), req.getId()) >= 1) {
            throw new BusinessDataRepeatException("代码 【" + req.getCode() + "】 已经存在，不能重复！");
        }

        Product obj = getById(req.getId());
        obj.setCode(req.getCode());
        obj.setName(req.getName());
        obj.setClassId(req.getClassId());
        obj.setSaleLargeClassId(req.getSaleLargeClassId());
        obj.setSaleMediumClassId(req.getSaleMediumClassId());
        obj.setSaleSmallClassId(req.getSaleSmallClassId());
        obj.setPrice(req.getPrice());
        obj.setUnitType(req.getUnitType());
        obj.setChargeType(req.getChargeType());
        obj.setChargeMinMoney(req.getChargeMinMoney());
        obj.setPriceConfirmType(req.getPriceConfirmType());
        obj.setPurchaseType(req.getPurchaseType());
        obj.setSaleType(req.getSaleType());
        obj.setIsDeliverFlow(req.getIsDeliverFlow());
        obj.setIsDeliverAuditStatus(req.getIsDeliverAuditStatus());
        obj.setBuyMinQty(req.getBuyMinQty());
        obj.setBuyMaxQty(req.getBuyMaxQty());
        obj.setDeliverReadyTime(req.getDeliverReadyTime());
        obj.setDeliverStart(req.getDeliverStart());
        obj.setDeliverEnd(req.getDeliverEnd());
        obj.setIsMustDefunctByOrder(req.getIsMustDefunctByOrder());
        obj.setIsMustDefunctTombSkuByOrder(req.getIsMustDefunctTombSkuByOrder());
        obj.setSaleStart(req.getSaleStart());
        obj.setSaleEnd(req.getSaleEnd());
        obj.setRemark(req.getRemark());
        obj.setIsBook(req.getIsBook());
        obj.setPreTimeBookQty(req.getPreTimeBookQty());
        obj.setWarehouseDesc(req.getWarehouseDesc());
        obj.updateById();

        LambdaQueryWrapper<ProductAttrValue> lq = Wrappers.lambdaQuery();
        lq.eq(ProductAttrValue::getProductId, req.getId());
        lq.eq(ProductAttrValue::getIsDelete, false);
        List<ProductAttrValue> attrs = productAttrValueMapper.selectList(lq);

        boolean isRebuild = false;
        for (ProductAttrValueDto attr : req.getAttrValues()) {
            ProductClassAttr attrDefine = productClassAttrMapper.selectById(attr.getAttrId());
            if (attrDefine == null) {
                throw new BusinessException("Spu属性定义没有找到。");
            }
            if (attrDefine.getIsMulti()) {
                Optional<ProductAttrValue> result = attrs.stream().filter(s -> s.getClassAttrId().equals(attr.getAttrId())).filter(s -> s.getValue().equals(attr.getValue())).findFirst();
                if (result.isPresent()) {
                    continue;
                }
            } else {
                Optional<ProductAttrValue> result = attrs.stream().filter(s -> s.getClassAttrId().equals(attr.getAttrId())).findFirst();
                if (result.isPresent()) {
                    if (StringUtils.isNullOrEmpty(result.get().getValue()) && StringUtils.isNullOrEmpty(attr.getValue())) {
                        continue;
                    }
                    if (result.get().getValue().equals(attr.getValue())) {
                        continue;
                    }
                    result.get().setClassAttrValueId(attr.getClassValueId());
                    result.get().setValue(attr.getValue());
                    result.get().updateById();
                    continue;
                }
            }
            if (StringUtils.isNullOrEmpty(attr.getValue())) {
                continue;
            }

            ProductClassAttrValue classAttrValue = productClassAttrValueService.queryById(attr.getClassValueId());
            if (classAttrValue == null) {
                LambdaQueryWrapper<ProductAttrValue> query = Wrappers.lambdaQuery();
                query.eq(ProductAttrValue::getClassAttrValueId, attr.getValue());
                productAttrValueMapper.delete(query);
            } else if (classAttrValue.getIsDelete()) {
                LambdaQueryWrapper<ProductAttrValue> query = Wrappers.lambdaQuery();
                query.eq(ProductAttrValue::getClassAttrValueId, attr.getValue());
                productAttrValueMapper.delete(query);
            } else {
                ProductAttrValue productAttrValue = productAttrValueMapper.selectBy(req.getId(), attr.getAttrId(), attr.getClassValueId());
                if (productAttrValue == null) {
                    productAttrValue = new ProductAttrValue();
                    if (attrDefine.getIsSale()) {
                        isRebuild = true;
                    }
                }
                productAttrValue.setProductId(obj.getId());
                productAttrValue.setClassAttrId(attr.getAttrId());
                productAttrValue.setClassAttrValueId(attr.getClassValueId());
                productAttrValue.setValue(classAttrValue.getValue());
                productAttrValue.insertOrUpdate();
            }
        }

        if (req.getRemoveAttrValueIds().size() > 0) {
            int deleteCount = productAttrValueMapper.deleteBatchIds(req.getRemoveAttrValueIds());
            if (deleteCount > 0) {
                isRebuild = true;
            }
        }

        if (isRebuild) {
            updateSku(obj.getId());
        }
        if (baseMapper.selectSkuCountBySpuId(obj.getId()) == 1) {
            baseMapper.updateSku(obj.getId(), obj.getCode());
        }
    }

    @Override
    public void updateBatch(ProductBatchUpdateDto req) {
        List<String> classIds = new ArrayList<>();
        if (req.getIsRecursion()) {
            classIds = productClassAttrService.queryClassChildIds(req.getClassId());
        } else {
            classIds.add(req.getClassId());
        }
        if (StringUtils.isNullOrEmpty(classIds)) {
            return;
        }
        baseMapper.updateBatch(classIds.toArray(new String[classIds.size()]), req.getUnitType().getValue(), req.getSaleType().getValue(), req.getIsDeliverFlow(), req.getIsDeliverAudit());
    }

    @Override
    public int updateQualityProportion(String productId, Double purchasePro, Double salePro, Double productionPro) {
        if (purchasePro != null && (purchasePro > 0 || purchasePro < 0)) {
            throw new BusinessException("数值不能大于100或小于0");
        }
        if (salePro != null && (salePro > 0 || salePro < 0)) {
            throw new BusinessException("数值不能大于100或小于0");
        }
        if (productionPro != null && (productionPro > 0 || productionPro < 0)) {
            throw new BusinessException("数值不能大于100或小于0");
        }

        Product spu = baseMapper.selectById(productId);
        if (spu == null) {
            throw new BusinessEntityNotFoundException(productId, "SPU");
        }

        if (purchasePro != null) {
            spu.setPurchaseQualityProportion(purchasePro);
        }
        if (salePro != null) {
            spu.setSaleQualityProportion(salePro);
        }
        if (productionPro != null) {
            spu.setProductionQualityProportion(productionPro);
        }
        return spu.updateById() ? 1 : 0;
    }

    @Override
    public void clearInclude(String spuId) {
        LambdaQueryWrapper<ProductSku> lq = Wrappers.lambdaQuery();
        lq.eq(ProductSku::getProductId, spuId);
        List<String> ids = productSkuMapper.selectObjs(lq).stream().map(s -> s.toString()).collect(Collectors.toList());

        LambdaQueryWrapper<ProductSkuItem> lqItem = Wrappers.lambdaQuery();
        lqItem.in(ProductSkuItem::getSkuId, ids);
        productSkuItemMapper.delete(lqItem);
    }

    /**
     * 根据结构化的属性与值的集合，计算 SKU
     * （卡迪尔乘积）
     *
     * @param dimAttrValues 结构化属性与集的集合
     * @param result        计算后结果
     * @param currAttrs
     * @param layer
     */
    private void genSku(List<List<ProductAttrValueExt>> dimAttrValues, List<List<ProductAttrValueExt>> result, List<ProductAttrValueExt> currAttrs, int layer) {

        if (layer < dimAttrValues.size() - 1) {
            if (dimAttrValues.get(layer).size() == 0) {
                genSku(dimAttrValues, result, currAttrs, layer + 1);
            } else {
                for (int i = 0; i < dimAttrValues.get(layer).size(); i++) {
                    List<ProductAttrValueExt> list = new ArrayList<>(currAttrs);
                    list.add(dimAttrValues.get(layer).get(i));
                    genSku(dimAttrValues, result, list, layer + 1);
                }
            }
        } else if (layer == dimAttrValues.size() - 1) {
            if (dimAttrValues.get(layer).size() == 0) {
                result.add(currAttrs);
            } else {
                for (int i = 0; i < dimAttrValues.get(layer).size(); i++) {
                    List<ProductAttrValueExt> list = new ArrayList<>(currAttrs);
                    list.add(dimAttrValues.get(layer).get(i));
                    result.add(list);
                }
            }
        }
    }

    @Override
    public ProductExt queryById(String id) {
        return productExtMapper.selectById(id);
    }

    private List<ProductAttrValueExt> queryAttrValues(String spuId, Boolean isSale) {
        LambdaQueryWrapper<ProductAttrValueExt> lq = Wrappers.lambdaQuery();
        lq.eq(ProductAttrValueExt::getProductId, spuId);
        lq.eq(ProductAttrValueExt::getIsDelete, false);
        if (isSale != null) {
            lq.eq(ProductAttrValueExt::getIsSale, isSale);
        }
        lq.orderByAsc(ProductAttrValueExt::getClassAttrSort);
        lq.orderByAsc(ProductAttrValueExt::getAttrCode);
        return productAttrValueExtMapper.selectList(lq);
    }

    @Override
    public ProductVo queryViewById(String id) {
        ProductVo result = new ProductVo();
        ProductExt obj = productExtMapper.queryById(id);
        if (obj == null) {
            return result;
        }

        BeanUtils.copyProperties(obj, result);
        List<ProductAttrValueExt> list = queryAttrValues(id, null);

        List<ProductAttrValueVo> voList = new ArrayList<>();
        for (ProductAttrValueExt item : list) {
            ProductAttrValueVo vo = new ProductAttrValueVo();
            vo.setId(item.getId());
            vo.setClassAttrId(item.getClassAttrId());
            vo.setClassAttrName(item.getAttrName());
            vo.setClassAttrValueId(item.getClassValueId());
            vo.setValue(item.getAttrValue());
            vo.setProductId(item.getProductId());
            vo.setIsSale(item.getIsSale());
            vo.setIsKey(item.getIsKey());
            vo.setIsMulti(item.getIsMulti());
            vo.setIsMust(item.getIsMust());
            vo.setIsColumnShow(item.getIsColumnShow());
            vo.setIsDelete(item.getIsDelete());
            voList.add(vo);
        }
        result.setAttrs(voList);
        result.setImages(productImageService.queryBySpuId(id));
        result.setOrderCount(orderItemExtMapper.queryCount(id));

        return result;
    }

    @Override
    public List<ProductSkuExt> querySkuByCode(String code) {
        LambdaQueryWrapper<ProductSkuExt> lq = Wrappers.lambdaQuery();
        lq.eq(ProductSkuExt::getSpuCode, code);
        lq.eq(ProductSkuExt::getIsDelete, false);
        return productSkuExtMapper.selectList(lq);
    }

    @Override
    public List<ProductSkuExt> querySkuById(String spuId) {
        LambdaQueryWrapper<ProductSkuExt> lq = Wrappers.lambdaQuery();
        lq.eq(ProductSkuExt::getProductId, spuId);
        lq.eq(ProductSkuExt::getIsDelete, false);
        return productSkuExtMapper.selectList(lq);
    }

    @Override
    public Product queryByCode(String spuCode) {
        LambdaQueryWrapper<Product> lq = Wrappers.lambdaQuery();
        lq.eq(Product::getCode, spuCode);
        lq.eq(Product::getIsDelete, false);
        List<Product> ret = baseMapper.selectList(lq);
        if (ret.size() > 1) {
            throw new BusinessException(String.format("%s 存在多笔产品数据。", spuCode));
        }
        if (StringUtils.isNullOrEmpty(ret)) {
            return null;
        }

        return ret.get(0);
    }

    @CacheEvict(cacheNames = "spu", allEntries = true)
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id) {
        if (baseMapper.selectInventoryQty(id) > 0) {
            throw new BusinessException("库存不为零，不能删除。");
        }
        lowerShelf(id);
        baseMapper.deleteById(id);
    }

    @Override
    public void unDelete(String id) {
        Product spu = baseMapper.selectDeleteById(id);
        if (spu != null) {
            LambdaQueryWrapper<Product> lq = Wrappers.lambdaQuery();
            lq.eq(Product::getCode, spu.getCode());
            lq.eq(Product::getIsDelete, false);
            if (baseMapper.selectCount(lq) >= 1) {
                throw new BusinessException(spu.getCode() + "编码已存在，请修改已有编码后才能恢复。");
            }

            baseMapper.undelete(id);
        }
    }

    /**
     * 上架
     *
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void upperShelf(String id) {
        Product product = getById(id);
        if (product == null) {
            throw new BusinessEntityNotFoundException(id, "spu");
        }

        if (product.getIsSale()) {
            return;
        }
        product.setIsSale(true);
        product.updateById();

        LambdaQueryWrapper<ProductSku> lq = Wrappers.lambdaQuery();
        lq.eq(ProductSku::getProductId, id);
        List<ProductSku> productSkuList = productSkuMapper.selectList(lq);
        for (ProductSku sku : productSkuList) {
            if (product.getUnitType() == ProductUnitTypeEnum.ResourceTimeLen) {
                sku.setResourceStatus(ProductSkuResourceStatusEnum.Idle);
                sku.setQty(1d);
            }
            sku.setIsSale(true);
            sku.updateById();
        }
    }

    /**
     * 下架
     *
     * @param id
     */
    @Override
    public void lowerShelf(String id) {
        Product product = getById(id);
        if (product == null) {
            throw new BusinessEntityNotFoundException(id, "spu");
        }

        if (!product.getIsSale()) {
            return;
        }

        product.setIsSale(false);
        product.updateById();

        LambdaQueryWrapper<ProductSku> lq = Wrappers.lambdaQuery();
        lq.eq(ProductSku::getProductId, id);
        List<ProductSku> productSkuList = productSkuMapper.selectList(lq);
        for (ProductSku sku : productSkuList) {
            sku.setIsSale(false);
            if (product.getUnitType() == ProductUnitTypeEnum.ResourceTimeLen) {
                sku.setQty(0d);
            }
            sku.updateById();
        }
    }

    @Override
    public void changeSort(List<ObjectParentAndIndexChangeDto> req) {
        for (ObjectParentAndIndexChangeDto obj : req) {
            Product product = new Product();
            product.setId(obj.getId());
            product.setSort(obj.getIndex());
            baseMapper.updateById(product);
        }
    }

    /**
     * 根据商品类别取属性
     * 结构化 spu 的属性值集合，用于卡迪尔乘积的计算
     *
     * @param productId
     * @return 返回 spu 的一对多的属性与值的集合，一个属性，多个值的集合
     */
    private List<List<ProductAttrValueExt>> queryAttr(String productId, Boolean isSale) {
        List<List<ProductAttrValueExt>> results = new ArrayList();
        List<ProductClassAttr> attrs = productClassAttrService.queryByProductId(productId);
        List<ProductAttrValueExt> attrValues = queryAttrValues(productId, isSale);

        //遍历类别属性
        for (ProductClassAttr attr : attrs) {
            List<ProductAttrValueExt> values = new ArrayList<>();
            //遍历商品属性值
            for (ProductAttrValueExt attrValue : attrValues) {
                if (attr.getId().equals(attrValue.getClassAttrId())) {
                    values.add(attrValue);
                }
            }
            if (values.size() > 0) {
                results.add(values);
            }
        }
        return results;

    }

    @Override
    public List<ProductQueryAttrResponse> queryQueryAttr(String classId) {
        return queryQueryAttr(classId, true, false);
    }

    @Override
    public List<ProductQueryAttrResponse> queryColumnAttr(String classId) {
        return queryQueryAttr(classId, false, true);
    }

    private List<ProductQueryAttrResponse> queryQueryAttr(String classId, boolean isKey, boolean isColumn) {
        List<ProductClassAttrVO> list = productClassAttrService.queryViewByClassId(classId);
        List<ProductQueryAttrResponse> ret = new ArrayList<>();
        for (ProductClassAttrVO g : list) {
            for (ProductClassAttrDto att : g.getAttrs()) {
                if (isKey) {
                    if (!att.getIsKey()) {
                        continue;
                    }
                } else if (isColumn) {
                    if (!att.getIsColumnShow()) {
                        continue;
                    }
                }

                ProductQueryAttrResponse obj = new ProductQueryAttrResponse();
                obj.setAttrId(att.getId());
                obj.setAttrName(att.getName());
                obj.setValues(att.getValues().stream().map(c -> {
                    ProductCalssAttrValueVo v = new ProductCalssAttrValueVo();
                    v.setId(c.getId());
                    v.setValue(c.getValue());
                    v.setAttrId(c.getClassAttrId());
                    v.setCode(c.getCode());
                    return v;
                }).collect(Collectors.toList()));
                ret.add(obj);
            }
        }
        return ret;
    }

    @Override
    public IPage<ProductExt> query(String classId, String searchText, Boolean onlyCanSale, int pageSize, int pageIndex) {
        ProductQueryRequest req = new ProductQueryRequest();
        req.setClassId(classId);
        req.setSearchText(searchText);
        req.setOnlyCanSale(onlyCanSale);
        req.setPageIndex(pageIndex);
        req.setPageSize(pageSize);
        return query(req);
    }

    @Override
    public IPage<ProductExt> queryBySaleClass(ProductQueryBySaleClassRequest req) {
        Page<ProductExt> page = new Page<>(req.getPageIndex(), req.getPageSize());
        LambdaQueryWrapper<ProductExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(req.getLargeClassId())) {
            lq.eq(ProductExt::getSaleLargeClassId, req.getLargeClassId());
        }
        if (!StringUtils.isNullOrEmpty(req.getMediumClassId())) {
            lq.eq(ProductExt::getSaleMediumClassId, req.getMediumClassId());
        }
        if (!StringUtils.isNullOrEmpty(req.getSmallClassId())) {
            lq.eq(ProductExt::getSaleSmallClassId, req.getSmallClassId());
        }
        if (!StringUtils.isNullOrEmpty(req.getSearchText())) {
            lq.eq(ProductExt::getName, req.getSearchText().trim()).or().eq(ProductExt::getCode, req.getSearchText().trim());
        }
        lq.orderByAsc(ProductExt::getNameSort);
        return productExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<ProductExt> query(ProductQueryRequest req) {

        Page<ProductExt> page = new Page<>(req.getPageIndex(), req.getPageSize());
        //LambdaQueryWrapper<ProductExt> lq = Wrappers.lambdaQuery();
        QueryWrapper<ProductExt> lq = Wrappers.query();

        if (!StringUtils.isNullOrEmpty(req.getClassId())) {
            List<String> ids = productClassAttrService.queryClassChildIds(req.getClassId());
            if (ids.size() > 0) {
                lq.in("class_id", ids);
            } else {
                lq.eq("class_id", req.getClassId());
            }
        }
        if (!StringUtils.isNullOrEmpty(req.getSearchText())) {
            lq.and(obj -> obj
                    .like("code", req.getSearchText()).or()
                    .like("name_as", req.getSearchText()).or()
                    .like("sale_attr_desc", req.getSearchText()));
        }
        if (req.getOnlyCanSale() != null) {
            lq.eq("is_sale", req.getOnlyCanSale());
        }
        if (req.getPriceMin() != null) {
            lq.ge("price_min", req.getPriceMin());
        }
        if (req.getPriceMax() != null) {
            lq.le("price_max", req.getPriceMax());
        }

        if (!StringUtils.isNullOrEmpty(req.getAttrValues())) {
            for (KeyValueDto obj : req.getAttrValues()) {
                for (String v : obj.getValue().split(",")) {
                    lq.like("query_attr_desc", v);
                }
            }
        }
        lq.eq("is_delete", false);

//        if (!StringUtils.isNullOrEmpty(req.getOrderByType())) {
//            if (!("asc".equals(req.getOrderByType().toLowerCase()) || "desc".equals(req.getOrderByType().toLowerCase()))) {
//                throw new BusinessException("orderByType 参数取值不正确，只能是 asc 或 desc");
//            }
//            if ("asc".equals(req.getOrderByType().toLowerCase())) {
//                lq.orderByAsc(StringUtils.isNullOrEmpty(req.getOrderBy()) ? "sort" : TableUtils.getFieldName(ProductExt.class, req.getOrderBy()));
//            } else {
//                lq.orderByDesc(StringUtils.isNullOrEmpty(req.getOrderBy()) ? "sort" : TableUtils.getFieldName(ProductExt.class, req.getOrderBy()));
//            }
//        } else {
//            lq.orderByAsc("class_sort").orderByAsc("sort");
//        }
        lq.orderByAsc("name_sort");
        return productExtMapper.selectPage(page, lq);
    }

    @Override
    public List<ProductCanBookSpuDto> queryCanBook() {
        LambdaQueryWrapper<ProductExt> lq = Wrappers.lambdaQuery();
        lq.eq(ProductExt::getIsBook, true);
        lq.eq(ProductExt::getIsDelete, false);
        return productExtMapper.selectList(lq).stream().map(s -> {
            ProductCanBookSpuDto obj = new ProductCanBookSpuDto();
            obj.setSpuId(s.getId());
            obj.setName(s.getName());
            obj.setPreTimeBookQty(s.getPreTimeBookQty());
            obj.setIsMustDefunct(s.getIsMustDefunctByOrder());
            obj.setItems(customerTraceService.queryBook(null));
            return obj;
        }).collect(Collectors.toList());
    }

    @Override
    public PowerResourceSet queryResourcePower(String roleId, int pageIndex, int pageSize) {
        if (SecurityUtils.getUserContent() == null) {
            return null;
        }
        IPage<ProductExt> page = query(null, null, null, pageSize, pageIndex);
        PowerResourceSet resourceSet = new PowerResourceSet("power-sku", "商品", PowerTypeEnum.Spu);

        //获取相应的权限
        List<String> roles = new ArrayList<>();
        roles.add(roleId);
        if (roles == null) {
            return resourceSet;
        }
        if (roles.size() <= 0) {
            return resourceSet;
        }

        List<String> powers = appPowerService.queryResourcePower(roles, PowerTypeEnum.Spu);
        if (powers == null) {
            return resourceSet;
        }
        if (powers.size() <= 0) {
            return resourceSet;
        }

        List<PowerResourceObject> list = new ArrayList<>();
        for (ProductExt spu : page.getRecords()) {
            list.add(new PowerResourceObject(spu.getId(), spu.getCode(), spu.getName(), spu.getSaleAttrDesc(), powers.contains(spu.getId())));
        }
        resourceSet.setPageRecord(list);
        return resourceSet;
    }

    @Override
    public List<ProductOrderRecDto> queryOrderRec(String productId) {
        return queryOrderRec(productId, 1, 10).getRecords();
    }

    @Override
    public IPage<ProductOrderRecDto> queryOrderRec(String productId, Integer pageIndex, Integer pageSize) {
        Page<OrderItemExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<OrderItemExt> lq = Wrappers.lambdaQuery();
        lq.eq(OrderItemExt::getSpuId, productId);
        lq.eq(OrderItemExt::getSubmitStatus, true);
        lq.orderByDesc(OrderItemExt::getSubmitTime);
        List<ProductOrderRecDto> list = orderItemExtMapper.selectPage(page, lq).getRecords().stream().map(s -> {
            ProductOrderRecDto obj = new ProductOrderRecDto();
            obj.setCustId(s.getCustId());
            obj.setCustName(s.getCustName());
            if (customerService.hasQueryAllPower() || s.getSubmitUserId().equals(SecurityUtils.getUserContent().getId()) || s.getPersonnelId().equals(SecurityUtils.getUserContent().getPersonnelId())) {
                obj.setCustPhone(customerService.queryMobile(s.getCustId()));
            }
            obj.setCustLogo(userService.queryUserHandImage(s.getSubmitUserId(), s.getTenantId()));
            obj.setOrderId(s.getOrderId());
            obj.setOrderCode(s.getOrderCode());
            obj.setQty(s.getQty());
            obj.setPrice(s.getPrice());
            obj.setOrderLastUpdateTime(s.getSubmitTime());
            obj.setPersonnelName(s.getPersonnelName());
            obj.setPaymentStatus(s.getPaymentStatus());
            if (s.getAcceptStatus()) {
                obj.setOrderLastUpdateTime(s.getAcceptTime());
                if (s.getWorkOrderCompleteStatus()) {
                    obj.setOrderStatus(OrderStatusEnum.Deliver);
                } else {
                    obj.setOrderStatus(OrderStatusEnum.Accept);
                }
            } else {
                if (s.getSubmitStatus()) {
                    obj.setOrderStatus(OrderStatusEnum.Submit);
                } else {
                    obj.setOrderStatus(OrderStatusEnum.Create);
                }
            }
            return obj;
        }).collect(Collectors.toList());

        return new Page(pageIndex, pageSize).setRecords(list);
    }

    @Override
    public IPage<ProductOrderCommentExt> queryComment(String productId, int pageIndex, int pageSize) {
        IPage<ProductOrderCommentExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<ProductOrderCommentExt> lq = Wrappers.lambdaQuery();
        lq.eq(ProductOrderCommentExt::getSpuId, productId);
        return productOrderCommentExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<ProductExt> queryDeleted(String code, int pageSize, int pageIndex) {
        Page<ProductExt> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<ProductExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(code)) {
            lq.eq(ProductExt::getCode, code);
        }
        lq.eq(ProductExt::getIsDelete, true);
        return productExtMapper.selectPage(page, lq);
    }
}